#ifndef STRING_H
#define STRING_H

#include <cstddef>
#include <cstring>

class String
{
friend String operator+(const String& lhs, const String& rhs);
public:
    String() : data_(nullptr), capacity_(0), size_(0)
    {}

    String(const char* str)
    {
        size_ = strlen(str);
        calculate_capacity(size_);
        data_ = new char[capacity_];
        memcpy(data_, str, size_);
    }

    String(const String& other)
    {
        capacity_ = other.capacity_;
        size_ = other.size_;
        data_ = new char[other.capacity_];
        memcpy(data_, other.data_, size_);
    }

    String(String&& other)
        : capacity_(other.capacity_),
          size_(other.size_),
          data_(other.data_)
    {
        other.capacity_ = 0;
        other.size_ = 0;
        other.data_ = nullptr;
    }

    ~String()
    {
        delete[] data_;
    }

    String& operator=(const String& other)
    {
        if (this == &other) return *this;
        delete [] data_;
        capacity_ = other.capacity_;
        size_ = other.size_;
        data_ = new char[other.capacity_];
        memcpy(data_, other.data_, size_);
        return *this;
    }

    String& operator=(String&& other)
    {
        if (this == &other) return *this;
        capacity_ = other.capacity_;
        size_ = other.size_;
        data_ = other.data_;
        other.capacity_ = other.size_ = 0;
        other.data_ = nullptr;
        return *this;
    }

    size_t size() const { return size_; }

    char& operator[](int idx)
    {
        return data_[idx];
    }

    void push_back(const char c)
    {
        if (size_++ == capacity_) {
            calculate_capacity(size_);
            char *data = new char[capacity_];
            memcpy(data, data_, size_ - 1);
            delete[] data_;
            data_ = data;
        }
        data_[size_ - 1] = c;
    }

private:
    char *data_;
    size_t capacity_;
    size_t size_;

    void calculate_capacity(size_t size)
    {
        if (size == 0) {
            capacity_ = 0;
            return;
        }
        capacity_ = 1;
        while (capacity_ < size) {
            capacity_ = capacity_ << 1;
        }
    }
};

String operator+(const String& lhs, const String& rhs)
{
    String result;
    result.size_ = lhs.size_ + rhs.size_;
    result.calculate_capacity(result.size_);
    result.data_ = new char[result.capacity_];
    memcpy(result.data_, lhs.data_, lhs.size_);
    memcpy(result.data_ + lhs.size_, rhs.data_, rhs.size_);
    return result;
}

#endif /* STRING_H */
